// exe_yl_afterpulse.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <numeric>
#include <cmath>
#include <algorithm>

#include <boost/date_time/posix_time/posix_time.hpp>

#include <quigon.h>
#include "stk_para.h"
#include "yl_lidar.h"
#include "yl_lidar_io.h"
#include "basic_process.h"
#include "noise_filter.h"
#include "output_lidarpro.h"


using namespace std;
using namespace boost::posix_time;
using namespace quigon;

//yl_lidar_constant start_t, end_t, aod, low_dist, high_dist
int main(int argc, char* argv[])
{
	string start_t, end_t;
	double aod;
	double low_dist, high_dist;
	if (argc < 5)
	{
		cout << "usage: yl_afterpulse yyyymmddThhmmss yyyymmddThhmmss low_dist high_dist" << endl;
		cout << "The capital 'T' in the 'iso time string' is optional" << endl;
		exit(0);
	}
	else
	{
		start_t = argv[1];
		end_t = argv[2];
		low_dist = atof(argv[3]);
		high_dist = atof(argv[4]);
	}

	// Check the date_time format, if not iso string, add 'T' into it.
	if (start_t[8] != 'T')
		start_t.insert(8, 1, 'T');
	if (end_t[8] != 'T')
		end_t.insert(8, 1, 'T');

	time_duration aver_duration = from_iso_string(end_t) - from_iso_string(start_t);
	double aver_seconds = aver_duration.total_milliseconds() / 1000.0;
	// Load lidar parameters
	YL_Para para("../settings/yl_lidar_para.txt");

	size_t low_index = para.distance_i[low_dist];
	size_t high_index = para.distance_i[high_dist];

	// Loading the priori data
//  cout << "Loading priori data..." << endl;
//  Time_Serie fe_distance("../settings/lidar/stk_priori_distance.txt");
//  Time_Serie fe_value("../settings/lidar/stk_priori_value.txt");

	// Making a container for the data and import
	list<YL_Line> container;
	cout << "Importing data..." << endl;
	import(
	        container,
	        from_iso_string(start_t),       // boost::posix_time::from_iso_string
	        from_iso_string(end_t),     // take care of the "T" in the string
	        para
	);
	cout << "lines num: " << container.size() << endl;

	cout << "Making an averager" << endl;
	Average_Machine<YL_Line> aver(aver_seconds, yl_aver_attr);
	// Make a functor for correction, and more options are available
	// e.g. Correction<STK_Line> my_corr(para, Status::BACKGROUND | Status::AFTERPULSE | Status::DISTANCE);
	// default is doing every possible correction
	cout << "Making a corrector" << endl;
	Correction<YL_Line, YL_Para> corr(para, Status::ENERGY , false);

	// Make a filter
//    cout << "Making a filter ..." << endl;
//    Serie<string, double> filter_para("../settings/lidar/stk_filter.txt");
//    Noise_Filter_Proto filter(
//        filter_para["low_index"],
//        filter_para["high_index"],
//        filter_para["low_buddy_num"],
//        filter_para["high_buddy_num"],
//        para.zero_meter_index,
//        para.size - 1);
//    double trigger_value = filter_para["trigger_value"];
//    size_t lowest_trigger_index = filter_para["lowest_trigger_index"];

	aver(container);
	YL_Line the_line = container.front();
	corr(the_line);
//	filter(the_line, trigger_value, lowest_trigger_index);
	kick_minus(the_line);
	// do we need a filter here?

	Lidar_Profile afterpulse;
	afterpulse["bin_size"] = the_line["bin_size"];
	afterpulse["start_value"] = para.start_value;
	if (high_index > the_line.size() - 1)
		high_index = the_line.size() - 1;

	afterpulse.resize(high_index + 1);
	for (size_t i = 0; i <= high_index; ++i)
	{
		if (i < low_index)
			afterpulse[i] = 0;
		else
		{
			afterpulse[i] = the_line[i];
		}
	}

	string filename = string("../settings/calibration/yl_") + start_t + "_" + end_t + ".afterpulse.txt";
	afterpulse.save(filename);

	return 0;
}


